/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://gitee.com/newgolo/embedme.git
 * Copyright 2014~2020 @ ShenZhen ,China
*******************************************************************************/
#ifndef __JSON_DATA_H__
#define __JSON_DATA_H__

#include "cJSON.h"
#include <iostream>
#include "libemb/BaseType.h"
#include "libemb/Tracer.h"

namespace libembx{
using namespace libemb;
/**
 *  @file   JSONData.h   
 *  @class  JSONNode
 *  @brief  JSON结点类.
 */
class JSONNode{
DECL_CLASSNAME(JSONNode)
public:
    JSONNode();
    virtual ~JSONNode();
    JSONNode(const JSONNode& node);
    std::string serialize(bool fmt=false);
    bool hasSubNode(const std::string nodeName);
    bool isNullNode();
    bool isArrayNode();
    int getArraySize();
    JSONNode operator[](const std::string nodeName);
    JSONNode operator[](int index);
    bool toBool();
    int toInt();
    double toDouble();
    std::string toString();
    JSONNode toNode();
    bool setValue(bool value);
    bool setValue(int value);
    bool setValue(double value);
    bool setValue(const char* value);
    bool addSubNode(bool value,const std::string nodeName="");
    bool addSubNode(int value,const std::string nodeName="");
    bool addSubNode(double value,const std::string nodeName="");
    bool addSubNode(const char* value,const std::string nodeName="");
	template <typename T>
    bool addSubNode(libemb::Array<T>& array,const std::string nodeName="")
	{
	    if (m_object==NULL)
	    {
	        return addNullNode(nodeName);
	    }
	    auto pNode = std::make_shared<JSONNode>();
	    pNode->m_name = nodeName;
	    switch (array.type())
	    {
	        case BASETYPE_INTARRAY:
	            pNode->m_object = cJSON_CreateIntArray(NULL,0);
	            break;
	        case BASETYPE_DOUBLEARRAY:
	            pNode->m_object = cJSON_CreateDoubleArray(NULL,0);
	            break;
	        case BASETYPE_STRINGARRAY:
	            pNode->m_object = cJSON_CreateStringArray(NULL,0);
	            break;
	        default:
	            return false;
	    }
	    int asize = array.size();
	    for(auto i=0; i<asize; i++)
	    {
	        cJSON* item=NULL;
	        switch (array.type())
	        {
	            case BASETYPE_INTARRAY:
	            {
	            	IntArray* pArray = (IntArray*)&array;
	                item = cJSON_CreateNumber((*pArray)[i]);
	                break;
	            }
	            case BASETYPE_DOUBLEARRAY:
	            {
	            	DoubleArray* pArray = (DoubleArray*)&array;
	                item = cJSON_CreateNumber((*pArray)[i]);
	                break;
	            }
	            case BASETYPE_STRINGARRAY:
	            {
	            	StringArray* pArray = (StringArray*)&array;
	                item = cJSON_CreateString(CSTR((*pArray)[i]));
	                break;
	            }
	        }
	        cJSON_AddItemToArray(pNode->m_object, item);
	    }
	    cJSON_AddItemToObject(m_object, CSTR(nodeName), pNode->m_object);
		m_appendNodes.push_back(pNode);
	    return true;
	}
    bool addSubNode(std::shared_ptr<JSONNode> node,const std::string nodeName="");
private:
    bool addNullNode(const std::string nodeName="");
private:
	friend class JSONData;
    cJSON* m_object;
    std::string m_name;
    std::vector<std::shared_ptr<JSONNode>> m_appendNodes;
};
/**
 *  @file   JSONData.h   
 *  @class  JSONData
 *  @brief  JSON数据类.
 */
class JSONData{
DECL_CLASSNAME(JSONData)
public:
    JSONData();
    ~JSONData();
    std::shared_ptr<JSONNode> initWithObjectFormat();
    std::shared_ptr<JSONNode> initWithArrayFormat();
    std::shared_ptr<JSONNode> initWithDataString(const char* jdata);
    std::shared_ptr<JSONNode> getRootNode();
    bool saveAsFile(const std::string fileName,bool fmt=false);
    std::string serialize(bool fmt=false);
private:
    bool deleteAllNodes();
private:
    std::shared_ptr<JSONNode> m_rootNode;
};
}
#endif